<?php
/** @noinspection PhpUnused */
declare(strict_types=1);

namespace app\shop\logic;

use app\shop\library\ShopHelper;
use think\db\BaseQuery;
use think\helper\Arr;

#[\AllowDynamicProperties]  //兼容php8.2弃用动态属性创建
class BaseLogic
{
    /**
     * 构造相等查询
     * @param BaseQuery $query
     * @param array     $inputs 查询参数
     * @param array     $fields
     *                          <br>['查询参数中的字段' => '数据表中的字段']
     * @return BaseQuery
     */
    protected function buildEqualQuery(BaseQuery $query, array $inputs, array $fields): BaseQuery
    {
        $inputsQuery = $this->getValueByInputData($inputs, $fields);

        return $this->buildQuery($query, $inputsQuery, '=');
    }

    /**
     * 构造like查询
     * @param BaseQuery $query
     * @param array     $inputs ['输入字段' => '值']
     * @param array     $fields ['输入字段' => '查询字段']
     * @param string    $like_type
     *                          <br> 默认：%值% left: %值 right：值%
     * @return BaseQuery
     */
    protected function buildLikeQuery(BaseQuery $query, array $inputs, array $fields, string $like_type = ''): BaseQuery
    {
        $input_data = $this->getValueByInputData($inputs, $fields);

        $inputs = array_map(function ($value) use ($like_type) {
            match ($like_type) {
                'left' => $new_value = '%' . $value,
                'right' => $new_value = $value . '%',
                default => $new_value = '%' . $value . '%',
            };
            return $new_value;
        }, $input_data);

        return $this->buildQuery($query, $inputs, 'like');
    }

    /**
     * 构造or查询
     * @param BaseQuery $query
     * @param array     $inputs ['输入字段' => '值']
     * @param array     $fields ['输入字段' => '查询字段']
     * @return BaseQuery
     */
    protected function buildOrQuery(BaseQuery $query, array $inputs, array $fields): BaseQuery
    {
        $inputs = $this->getValueByInputData($inputs, $fields);

        return $this->buildQuery($query, $inputs, 'or');
    }


    /**
     * 获取操作符号和数据值
     * @param $input_data
     * @param $input_field
     * @param $default_operate
     * @return array
     */
    private function getOperateAndValue($input_data, $input_field, $default_operate): array
    {
        $allow_operates = ['>', '=', '<', '>=', '<=', '<>'];

        if (is_array($input_field)) {
            [$operate, $value] = $input_field;
            $operate = (in_array($operate, $allow_operates)) ? $operate : $default_operate;
            $value   = Arr::get($input_data, $value);
        } else {
            $operate = $default_operate;
            $value   = Arr::get($input_data, $input_field);
        }

        return [$operate, $value];
    }

    /**
     * 从输入数组中获取并构造区间数据
     * @param array $inputs
     * @param array $fields
     * /
     * @return array
     */
    private function getBetweenDataByInputData(array $inputs, array $fields): array
    {
        $data = [];

        $default_start_operate = '>=';
        $default_end_operate   = '<=';

        $to_value   = '';
        $to_operate = '';
        foreach ($fields as $key => $field) {
            //获取操作符和数据
            if (is_array($field)) {
                //多个值
                [$start, $end] = array_pad($field, 2, null);
                [$from_operate, $from_value] = self::getOperateAndValue($inputs, $start, $default_start_operate);
                [$to_operate, $to_value] = self::getOperateAndValue($inputs, $end, $default_end_operate);
            } else {
                //单个值
                [$from_operate, $from_value] = self::getOperateAndValue($inputs, $field, $default_start_operate);
            }
            // 存储数据
            if (!ShopHelper::is_empty($from_value)) {
                $data[$key]['from']['operate'] = $from_operate;
                $data[$key]['from']['value']   = $from_value;
            }
            if (!ShopHelper::is_empty($to_value)) {
                $data[$key]['to']['operate'] = $to_operate;
                $data[$key]['to']['value']   = $to_value;
            }
        }

        return $data;
    }

    /**
     * 构造区间类型查询
     * @param BaseQuery $query
     * @param array     $inputs
     * @param array     $fields
     * @param string    $type
     * <br>默认：where date：whereDate time：whereTime
     * @return BaseQuery
     */
    private function buildBetweenTypeQuery(BaseQuery $query, array $inputs, array $fields, string $type = ''): BaseQuery
    {
        $between_data = self::getBetweenDataByInputData($inputs, $fields);

        $query->where(function ($query) use ($between_data, $type) {
            foreach ($between_data as $time_field => $value) {
                $query->where(function ($query) use ($time_field, $value, $type) {
                    $time_flags = ['from', 'to'];
                    foreach ($time_flags as $time_flag) {
                        $field = Arr::get($value, $time_flag);
                        if (!ShopHelper::is_empty($field) && !ShopHelper::is_empty(Arr::get($field, 'value'))) {
                            $whereType = match ($type) {
                                default => 'where',
                                'date' => 'whereDate',
                                'time' => 'whereTime',
                            };
                            $query->$whereType($time_field, Arr::get($field, 'operate'), Arr::get($field, 'value'));
                        }
                    }
                });
            }
        });

        return $query;
    }

    /**
     * 日期区间查询
     * @param BaseQuery $query
     * @param array     $inputs
     * @param array     $fields 格式：
     *                          <br>['字段’=> '值'] 或
     *                          <br>['字段’=> ['值1','值2'] ] 或
     *                          <br>['字段’=> ['符号','值1'], ['符号','值2'] ]
     * @return BaseQuery
     */
    protected function buildDateQuery(BaseQuery $query, array $inputs, array $fields): BaseQuery
    {
        return self::buildBetweenTypeQuery($query, $inputs, $fields, 'date');
    }

    /**
     * 时间区间查询
     * @param BaseQuery $query
     * @param array     $inputs
     * @param array     $fields 格式：
     *                          <br>['字段’=> '值'] 或
     *                          <br>['字段’=> ['值1','值2'] ] 或
     *                          <br>['字段’=> ['符号','值1'], ['符号','值2'] ]
     * @return BaseQuery
     */
    protected function buildTimeQuery(BaseQuery $query, array $inputs, array $fields): BaseQuery
    {
        return self::buildBetweenTypeQuery($query, $inputs, $fields, 'time');
    }

    /**
     * 区间查询
     * @param BaseQuery $query
     * @param array     $inputs
     * @param array     $fields
     * <br>['数据表字段’=> '字段'/ ['字段1','字段2']  / [['符号','字段1'], ['符号','字段2']]
     * @return BaseQuery
     */
    protected function buildBetweenQuery(BaseQuery $query, array $inputs, array $fields): BaseQuery
    {
        return self::buildBetweenTypeQuery($query, $inputs, $fields);
    }

    /**
     * 从输入数组中获取查询字段和值
     * @param array $inputs
     * @param array $fields
     * @return array
     */
    private function getValueByInputData(array $inputs, array $fields): array
    {
        $data = [];
        foreach ($fields as $key => $field) {
            $value = Arr::get($inputs, $key);
            if (is_null($value) || ShopHelper::is_empty($value)) continue;
            if (is_string($value)) {
                $value = trim($value);
            }
            $data[$field] = $value;
        }

        return $data;
    }

    /**
     * 构造查询
     * @param BaseQuery $query
     * @param array     $inputsQuery
     * @param string    $type
     * @return BaseQuery
     */
    private function buildQuery(BaseQuery $query, array $inputsQuery, string $type): BaseQuery
    {
        $query->where(function ($query) use ($inputsQuery, $type) {
            foreach ($inputsQuery as $field => $value) {
                $query->where(function ($query) use ($field, $value, $type) {
                    $search_field = explode('|', $field);
                    //多个字段查询一个值 拼接or查询, 单个字段拼接and查询
                    $where_type = count($search_field) > 1 ? 'WhereOr' : 'where';
                    array_map(function ($field_str) use ($query, $value, $type, $where_type) {
                        match ($type) {
                            default => $query->$where_type($field_str, $value),
                            'like' => $query->$where_type($field_str, 'like', $value),
                        };
                    }, $search_field);
                });
            }
        });

        return $query;
    }

    /**
     *关联查询
     * @param       $relation
     * @param       $query
     * @param array $inputs
     * @param array $fields
     * @return BaseQuery
     */
    protected function buildRelationQuery($relation, $query, array $inputs, array $fields): BaseQuery
    {
        $input_data = self::getValueByInputData($inputs, $fields);

        $query->whereHas($relation, function ($query) use ($input_data) {
            foreach ($input_data as $field => $value) {
                $query->where([$field => $value]);
            }
        });

        return $query;
    }

    /**
     * 构造findInSet查询
     * @param BaseQuery $query
     * @param array     $inputs 请求参数
     * @param array     $fields ['输入字段' => '查询字段']
     * @return BaseQuery
     */
    protected function buildFindInSetQuery(BaseQuery $query, array $inputs, array $fields): BaseQuery
    {
        $inputs = $this->getValueByInputData($inputs, $fields);

        return $this->buildQuery($query, $inputs, 'find_in_set');
    }
}
